﻿
package solver 
{

	/**
	 * The SodokySolver algorithm
	 * @author eKameleon
	 */
	public class SodokuSolver 
	{
		
		/**
		 *  Call action(elem) on each element of sequence.
		 *  When action(elem) returns exactly "false", stop iterations and return false.
		 *  Otherwise, when there are no elements in the sequence or all action(elem) returns !== false, return true.
		 *  sequence is either Array, string or function. In the latter case the function 
		 *  will be called as sequence(action) and it must implement the loop semantic itself.
		 */
		public static function loop( sequence:* , action:Function ):Boolean
		{
    		
    		var n:uint ;
    		var i:uint ;
    		
    		if ( sequence is Function )
    		{
        		return (sequence as Function)(action) ;
    		}
			
			if ( sequence === undefined ) 
        	{
        		return true;
    		}
    		else if (sequence is String) 
    		{
        		sequence = new String( sequence ) ;
        	}
		    else if ( sequence is Object ) 
		    {
        		if (sequence is Array) 
        		{
            		n = sequence.length;
            		for (i = 0 ; i != n ; ++i ) 
            		{
                		if ( action(sequence[i]) === false)
                		{
                    		return false;
                		}
            		}
            		return true;
        		}
    		} 
    		else 
    		{
        		throw new Error("Unsupported sequence type : " + sequence ) ;
    		}
    		
    		if ( !( sequence is String ) )
    		{
        		throw new Error("Unsupported sequence object") ;
    		}
    		
    		n = sequence.length;
    		for (i = 0; i != n; ++i) 
    		{
	        	if (action(sequence.charAt(i)) === false)
        		{
	        		return false;
        		}
    		}
			return true;
		}
		
		/**
		 * Returns a new sequence where each element is mapper(elem).
		 * @return a new sequence where each element is mapper(elem).
		 */ 
		public static function smap( sequence:* , mapper:Function ):Function
		{
    		return function( action:Function ):void
    		{
    			loop
    			( 
    				sequence , 
    				function( elem:* ):void
    				{ 
	    				action(mapper(elem)) ; 
    				} 
    			);
    		} ;
		}
		
		public static function zip( a:*, b:* ):Function
		{
    		
    		var n:uint = Math.min( a.length, b.length ) ;
    		
    		return function( action:Function ):Boolean 
    		{ 
        		for (var i:uint = 0; i < n; i++) 
        		{
	            	if (action(a[i], b[i]) === false)
            		{
	                	return false;
            		}
        		}
        		return true;
    		} ;
   		}
	
	}

}
